package brainbots;

import javax.swing.SwingUtilities;

public class InteractiveSimulator implements Runnable{
	private World world;
	private boolean pauseFlag;
	private Thread redrawThread;
	
	public void setWorld(World world) {
		setPause(true);
		synchronized(this){
			this.world = world;
			freshSimulation = true;
			resetTime();
			notify();//wake up the simulator thread, if it is waiting
		}
	}
	
	@Override
	public void run() {
		stopRequested = false;
		time = 0;
		try {
			simulate();
		} catch (InterruptedException e) {
			System.err.println("Warning: interrupted exception while simulating");
			e.printStackTrace();
		}
		
	}
	
	public double getTime() {
		return time;
	}
	public void resetTime(){
		time = 0.0;
	}
	
	public void setPause(boolean flag){
		pauseFlag = flag;
		synchronized(this){
			notify();
		}
	}

	
	private double dt=0.01;//simulation time step, in model time
	private double timeRatio=0;//coeff to convert from real time (ms) to model time
	private boolean stopRequested = false;
	private double time;
	private int delay=10;
	private boolean freshSimulation=false;
	
	public double getTimeRatio() {
		return timeRatio;
	}
	
	
	public void setDelay(int delay) {
		if (delay<0)
			throw new RuntimeException("Delay must be positive");
		if (delay>1000){
			System.err.println("Warning: delay more than 1000, isn't it too slow?");
		}
		this.delay =delay; 
	}
	public int getDelay() {
		return delay;
	}
	public void requestStop(){
		stopRequested = true;
		synchronized(this){
			notify();
		}
	}
	
	private synchronized void simulate() throws InterruptedException {
		long oldTime = System.currentTimeMillis();
		
			
		int updateTimerEvery = 10;//how much steps to do before updating timer (do not update it every time, ut would be too fast)
		while (true){//exit when stop is requested			
			while ((world == null || pauseFlag) && ! stopRequested){
				this.wait();
				//System.out.println("waiting");
			}
			if (freshSimulation){
				freshSimulation = false;
				if (world != null && world.getBreeder() != null){
					synchronized(world){
						world.getBreeder().onStartSim();
					}
				}
			}
			if (stopRequested)
				break;
			
			for(int i =0;i<updateTimerEvery;++i){
				synchronized(world){
					world.simulate(dt);
				}
			}
		
			time += dt*updateTimerEvery;
			
			long newTime = System.currentTimeMillis();
			long dTime = newTime - oldTime;
			timeRatio = dTime/(dt*updateTimerEvery);
			if (delay>0){
				Thread.sleep(delay);
			}
		}
	}

	public void setDt(double d) {
		if (dt<0){
			throw new RuntimeException("Time grain can not be less than 0");
		}
		this.dt = d;
	}
	
	
}
